#include "OTAUpdater.h"
#include "EspressifHTTPClient.cpp"
#include "cJSON.h"
#include "esp_crt_bundle.h"
#include "esp_ota_ops.h"
#include "nvs.h"
#include "nvs_flash.h"
#include <string.h>

// 日志标签
static const char *TAG = "OTAUpdater";

OtaUpdater::OtaUpdater() :
	timeout_ms_(10000), update_available_(false) {
	m_http_client = new EspressifHTTPClient();
	m_http_client->connect(HOST, PORT);
	m_http_client->setHttpsEnabled(true);
	m_http_client->setCertificate(ROOT_CERT);
}

OtaUpdater::~OtaUpdater() {
}

/* 用于捕获系统事件的事件处理程序 */
void OtaUpdater::eventHandler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
	if (event_base == ESP_HTTPS_OTA_EVENT) {
		switch (event_id) {
		case ESP_HTTPS_OTA_START:
			ESP_LOGI(TAG, "OTA started");
			break;
		case ESP_HTTPS_OTA_CONNECTED:
			ESP_LOGI(TAG, "Connected to server");
			break;
		case ESP_HTTPS_OTA_GET_IMG_DESC:
			ESP_LOGI(TAG, "Reading Image Description");
			break;
		case ESP_HTTPS_OTA_VERIFY_CHIP_ID:
			ESP_LOGI(TAG, "Verifying chip id of new image: %d", *(esp_chip_id_t *)event_data);
			break;
		case ESP_HTTPS_OTA_DECRYPT_CB:
			ESP_LOGI(TAG, "Callback to decrypt function");
			break;
		case ESP_HTTPS_OTA_WRITE_FLASH:
			ESP_LOGD(TAG, "Writing to flash: %d written", *(int *)event_data);
			break;
		case ESP_HTTPS_OTA_UPDATE_BOOT_PARTITION:
			ESP_LOGI(TAG, "Boot partition updated. Next Partition: %d", *(esp_partition_subtype_t *)event_data);
			break;
		case ESP_HTTPS_OTA_FINISH:
			ESP_LOGI(TAG, "OTA finish");
			break;
		case ESP_HTTPS_OTA_ABORT:
			ESP_LOGI(TAG, "OTA abort");
			break;
		}
	}
}

bool OtaUpdater::checkForUpdate() {
	char deviceId[16];
	Helper::generateDeviceId(deviceId);
	char url[256];
	snprintf(url, sizeof(url), OTA_VERSION_URI, deviceId);
	ESP_LOGI(TAG, "Checking for update from: %s", url);

	int status = m_http_client->get(url);
	if (status == 200) {
		std::string currentVersion = getCurrentFirmwareVersion();
		std::string response = m_http_client->getResponseBody();
		cJSON *root = cJSON_Parse(response.c_str());
		if (!root) {
			ESP_LOGE(TAG, "解析升级响应失败: %s", response.c_str());
			return false;
		}
		cJSON *ver_item = cJSON_GetObjectItem(root, "version");
		if (ver_item->valuestring != NULL && strcmp(currentVersion.c_str(), ver_item->valuestring) != 0) {
			// 初始化
			memset(&m_ota_firmware_info, 0, sizeof(m_ota_firmware_info));
			Helper::copy_cjson_number(&m_ota_firmware_info.data_size, root, "dataSize");
			Helper::copy_cjson_string(m_ota_firmware_info.version, sizeof(m_ota_firmware_info.version), root, "version");
			Helper::copy_cjson_string(m_ota_firmware_info.checksum, sizeof(m_ota_firmware_info.checksum), root, "checksum");
			Helper::copy_cjson_string(m_ota_firmware_info.checksum_algorithm, sizeof(m_ota_firmware_info.checksum_algorithm), root, "checksumAlgorithm");
			Helper::copy_cjson_string(m_ota_firmware_info.package_id, sizeof(m_ota_firmware_info.package_id), root, "packageId");
			ESP_LOGI(TAG, "id:%s,version:%s,checksum:%s,data_size:%d.",
					 m_ota_firmware_info.package_id,
					 m_ota_firmware_info.version,
					 m_ota_firmware_info.checksum,
					 m_ota_firmware_info.data_size);

			cJSON_Delete(root);
			return true;
		}
		cJSON_Delete(root);
	} else {
		ESP_LOGE(TAG, "升级服务不可用 http status:%d", status);
	}
	return false;
}

esp_err_t OtaUpdater::validateImageHeader(esp_app_desc_t *app_desc) {
	// 1. 魔数验证：确保是有效的ESP32固件
	if (app_desc->magic_word != ESP_APP_DESC_MAGIC_WORD) {
		ESP_LOGE("SHA256", " Magic word ESP_APP_DESC_MAGIC_WORD");
		return ESP_FAIL; // 不是有效的固件
	}
	// 2. 版本一致性验证：确保下载的就是请求的版本
	if (strcmp(app_desc->version, m_ota_firmware_info.version) != 0) {
		ESP_LOGE(TAG, "app_desc-> version:5s%s  m_ota_firmware_info->version:%s ", app_desc->version, m_ota_firmware_info.version);
		return ESP_FAIL; // 版本不一致
	}

	// 将二进制SHA256转换为字符串
	char actual_sha256[65];
	for (int i = 0; i < 32; i++) {
		sprintf(&actual_sha256[i * 2], "%02x", app_desc->app_elf_sha256[i]);
	}
	actual_sha256[64] = '\0';

	// 3. 不区分大小写比较sha256
	if (strcasecmp(actual_sha256, m_ota_firmware_info.checksum) != 0) {
		ESP_LOGE(TAG, "Mismatch! Actual: %s, Expected: %s", actual_sha256, m_ota_firmware_info.checksum);
		return ESP_ERR_INVALID_CRC;
	}
	return ESP_OK;
}

bool OtaUpdater::performUpdate() {
	ESP_ERROR_CHECK(esp_event_handler_register(ESP_HTTPS_OTA_EVENT, ESP_EVENT_ANY_ID, &OtaUpdater::eventHandler, NULL));

	char url[256];
	snprintf(url, sizeof(url), OTA_BIN_URL, m_ota_firmware_info.package_id);
	ESP_LOGI(TAG, "Starting OTA update from: %s", url);
	std::string full_url;
	full_url = "https://" + std::string(HOST) + ":" + std::to_string(PORT) + url;

	ESP_LOGI(TAG, "begin down ota url:%s", full_url.c_str());
	esp_http_client_config_t http_config = {};
	http_config.url = full_url.c_str();
	http_config.cert_pem = ROOT_CERT;
	http_config.keep_alive_enable = true;
	http_config.buffer_size = 10240;
	http_config.buffer_size_tx = 10240;

	esp_https_ota_config_t ota_config = {
		.http_config = &http_config,
	};

	// 获取OTA句柄进行自定义校验
	esp_https_ota_handle_t https_ota_handle = NULL;
	// 1. 初始化OTA（但还不开始写flash）
	esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);
	if (err != ESP_OK) {
		ESP_LOGE("OTA", "OTA begin failed");
		return false;
	}

	esp_app_desc_t app_desc = {};
	err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc);
	if (err != ESP_OK) {
		ESP_LOGE(TAG, "esp_https_ota_get_img_desc failed");
		esp_https_ota_abort(https_ota_handle);
		return false;
	}

	err = validateImageHeader(&app_desc);
	if (err != ESP_OK) {
		ESP_LOGE(TAG, "image header verification failed");
		esp_https_ota_abort(https_ota_handle);
		return false;
	}

	while (1) {
		err = esp_https_ota_perform(https_ota_handle);
		if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) {
			break;
		}
		// esp_https_ota_perform 会在每个数据块下载完成后返回，这样设计的好处是：
		// 1. 可以实时监控下载进度
		// 2. 可以实现断点续传功能
		// 3. 可以在下载过程中添加暂停、取消等控制逻辑
		// 4. 避免一次性占用过多内存，采用流式处理方式
		const size_t len = esp_https_ota_get_image_len_read(https_ota_handle);
		ESP_LOGI(TAG, "Image bytes read: %d", len);
		vTaskDelay(500 / portTICK_PERIOD_MS);
	}

	if (esp_https_ota_is_complete_data_received(https_ota_handle) != true) {
		// the OTA image was not completely received and user can customise the response to this situation.
		ESP_LOGE(TAG, "Complete data was not received.");
		esp_https_ota_abort(https_ota_handle);
	} else {
		esp_err_t ota_finish_err = esp_https_ota_finish(https_ota_handle);
		if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) {
			ESP_LOGI(TAG, "ESP_HTTPS_OTA upgrade successful. Rebooting ...");
			vTaskDelay(1000 / portTICK_PERIOD_MS);
			esp_restart();
		} else {
			if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED) {
				ESP_LOGE(TAG, "Image validation failed, image is corrupted");
			}
			ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed 0x%x", ota_finish_err);
		}
	}
	return false;
}

void OtaUpdater::setTimeout(int timeout_ms) {
	timeout_ms_ = timeout_ms;
}

const std::string &OtaUpdater::getError() const {
	return error_message_;
}

std::string OtaUpdater::getCurrentFirmwareVersion() {
	return FW_VERSION;
}